package twitter.RequestParser;


import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import twitter.TwitterLibrary.Utility;
import org.apache.log4j.*;
import Twitter.RequestSender.FrontendRequestSender;
/*********************************************
 * this class is designed for parse all the requests that front end server receives
 * @author fang
 *
 */
public class FrontendRequestParser {

	private FrontendRequestSender frontendSender = null;
	private DocumentBuilderFactory factory = null;
	private Document DOC_tweets = null;
	private HashMap<String, Document> versionCache = null;
	private HashMap<String, Integer> tagCache = null;
	private final ReentrantReadWriteLock rwl ;
	private final Lock r ;
	private final Lock w ;
	
	private XMLWriter xmlWriter;
	private XMLReader xmlReader;
	static Logger logger = Logger.getLogger(FrontendRequestParser.class);
	private Utility utility;
/*********************************************
 * Class constructor
 * @param end "connection"
 * @param rwl the read write lock which is used by front end server
 */
	public FrontendRequestParser(String end,ReentrantReadWriteLock rwl,Utility utility) {
		this.rwl=rwl;
		r=rwl.readLock();
		w=rwl.writeLock();
		BasicConfigurator.configure();

		factory = DocumentBuilderFactory.newInstance();
		xmlWriter = new XMLWriter(factory, versionCache, tagCache,rwl,utility);
		xmlReader = new XMLReader();
		frontendSender = new FrontendRequestSender(this.xmlWriter, this.xmlReader,utility);
		this.utility = utility;

	}
/***************************************************
 * set the version cache and hash tag cache for the front end server
 * @param versionCache:storing all the version information in the cache
 * @param tagCache:storing all the hash tag information in the cache
 */
	public void setCache(HashMap<String, Document> versionCache,
			HashMap<String, Integer> tagCache) {

		this.versionCache = versionCache;
		this.tagCache = tagCache;
	}
/**************************************
 * parsing the Http Get request
 * @param query:the query string
 * @return response string
 */
	public String responseGet(String query) {

		String result = "";

		if (!isNewRequest(query)) {

			r.lock();
			try {
				logger
						.info("reading the front end server cache and the lock information is : "
								+ rwl.toString());
				DOC_tweets = versionCache.get(query);
				result = xmlWriter.changeCached(DOC_tweets);

			} finally {
				r.unlock();
			}

		} else {

			HashMap<String, ArrayList<String>> results = frontendSender
					.searchStatusByTag(query);

			result = xmlWriter.writeTwitts(results);

		}
		return result;
	}
/****************************************************
 * parsing the http post request
 * @param newStatus : the new status 
 * @return :the response string
 */
	public String responsePost(String newStatus) {

		String result = frontendSender.addNewStatus(newStatus);
		ArrayList<String> flags = utility.getHashflag(newStatus);
		w.lock();
		try {
			logger
					.info("writing to the front end server cache and the lock information is : "
							+ rwl.toString());
			for (int i = 0; i < flags.size(); i++) {
				String flag = flags.get(i).toString();
				boolean contains = false;
				contains = versionCache.containsKey(flag);

				if (contains) {

					versionCache.remove(flag);
					tagCache.remove(flag);

				}
			}
		} finally {
			w.unlock();
		}

		return result;

	}
/****************************************************
 * to verify the request whether  is new or not
 * @param query
 * @return true or false
 */
	public boolean isNewRequest(String query) {

		int newestVersion = frontendSender.searchForVersion(query);

		r.lock();
		try {

			if (versionCache.containsKey(query)) {

				logger.info("reading the front end server cache");
				int currentVirsion = Integer.valueOf(tagCache.get(query));

				if (currentVirsion < newestVersion) {

					return true;
				} else {

					return false;
				}
			} else {

				return true;
			}
		} finally {
			r.unlock();
		}

	}

	

	

}
